﻿#pragma once

#ifndef BRIDGEANALYSIS_UTILS_H
#define BRIDGEANALYSIS_UTILS_H

// 初始化日志配置
void init_logging(std::string appPath = "");

// 线程安全动态库返回变量，每个线程分配一套变量
typedef struct tagThreadSafeReturnVars
{
    std::list<int32_t> vcodes;        // 支持多级错误信息
    std::list<std::string> vmessages; // 支持多级错误信息
    std::string dllReturn;
    tagThreadSafeReturnVars() : vcodes({}), vmessages({}), dllReturn("") {};
    tagThreadSafeReturnVars(const tagThreadSafeReturnVars &src) : vcodes(src.vcodes), vmessages(src.vmessages), dllReturn(src.dllReturn) {}
    tagThreadSafeReturnVars &operator=(const tagThreadSafeReturnVars &src)
    {
        vcodes = src.vcodes;
        vmessages = src.vmessages;
        dllReturn = src.dllReturn;
        return *this;
    }
} ThreadSafeReturnVars;

extern std::unordered_map<std::string, ThreadSafeReturnVars> __threadSafeReturnVarsMap;

// 获取当前毫秒时间戳
uint64_t now_ms();

// 获取当前进程ID
std::string getThreadId();

// 格式化字符串
const std::string _S_(const char *format, ...);

// UTF-8字符串转GBK字符串
std::string GBK(const std::string &strUTF8);

// GBK字符串转UTF-8字符串
std::string UTF8(const std::string &strGBK);

// 清除错误代码和错误信息
void clear_error();
bool has_error();

// 设置动态库返回的错误代码和错误信息
void set_error(int32_t code, const char *format);

template <class T>
std::string vector2String(std::vector<T> vect)
{
    std::stringstream ss;
    ss << "[";
    for (size_t i = 0; i < vect.size(); i++)
    {
        ss << vect[i];
        if (i != vect.size() - 1)
        {
            ss << ",";
        }
    }
    ss << "]";
    return ss.str();
}

// 动态库内部函数返回采用PUSH_ERROR
#define PUSH_ERROR(format, ...)                                                                     \
    do                                                                                              \
    {                                                                                               \
        std::string fname = std::filesystem::path(__FILE__).filename().string();                    \
        std::string _full_msg = _S_("\t--> [%s/%s/%d] - ", fname.c_str(), __FUNCTION__, __LINE__) + \
                                _S_(format, ##__VA_ARGS__);                                         \
        ::set_error(-1, _full_msg.c_str());                                                         \
    } while (0)

// 一般动态库还是最终返回前调用SET_ERROR
#define SET_ERROR(code, format, ...)                                                          \
    do                                                                                        \
    {                                                                                         \
        std::string fname = std::filesystem::path(__FILE__).filename().string();              \
        std::string _full_msg = _S_("[%s/%s/%d] - ", fname.c_str(), __FUNCTION__, __LINE__) + \
                                _S_(format, ##__VA_ARGS__);                                   \
        ::set_error(code, _full_msg.c_str());                                                 \
    } while (0)

// 区别于SET_ERROR，内部调用则增加\t--> 以显示错误产生的嵌套调用次序。
#define SET_ERROR_(code, format, ...)                                                                                             \
    do                                                                                                                            \
    {                                                                                                                             \
        std::string fname = std::filesystem::path(__FILE__).filename().string();                                                  \
        std::string _full_msg = _S_(innerCall ? "\t--> [%s/%s/%d] - " : "[%s/%s/%d] - ", fname.c_str(), __FUNCTION__, __LINE__) + \
                                _S_(format, ##__VA_ARGS__);                                                                       \
        ::set_error(code, _full_msg.c_str());                                                                                     \
    } while (0)

// 获取动态库返回的错误代码和错误信息(最终一条)
void get_error(int32_t *pCode, char **pMessage);

// 获取动态库返回的多级错误代码和错误信息
void get_errors(int32_t *vcodes, char **vmessages, int32_t bufferCount, int32_t *realCount);

// 获取运行程序的主目录
std::string getExecutableDirectory();

// 获取动态库自身路径
std::string getModulePath();

// 初始化 CRC64 表
void init_crc64_table();

// 计算 CRC64 值
uint64_t calculate_crc64(const char *data, size_t length);

#if false
#define CATCH_AND_RETURN(failReturn)                                                                                                                          \
    catch (std::exception & ex)                                                                                                                               \
    {                                                                                                                                                         \
        const boost::stacktrace::stacktrace *st = boost::get_error_info<traced>(ex);                                                                          \
        std::string szError;                                                                                                                                  \
        if (st)                                                                                                                                               \
        {                                                                                                                                                     \
            SET_ERROR(ERR_CODE_GENERAL_EXCEPTION, ERR_MESSAGE_GENERAL_EXCEPTION, (std::string(ex.what()) + "/" + boost::stacktrace::to_string(*st)).c_str()); \
        }                                                                                                                                                     \
        else                                                                                                                                                  \
        {                                                                                                                                                     \
            SET_ERROR(ERR_CODE_GENERAL_EXCEPTION, ERR_MESSAGE_GENERAL_EXCEPTION, ex.what());                                                                  \
        }                                                                                                                                                     \
        return failReturn;                                                                                                                                    \
    }                                                                                                                                                         \
    catch (const char *error)                                                                                                                                 \
    {                                                                                                                                                         \
        SET_ERROR(ERR_CODE_UNKNOWN_EXCEPTION, ERR_MESSAGE_UNKNOWN_EXCEPTION, error);                                                                          \
        return failReturn;                                                                                                                                    \
    }                                                                                                                                                         \
    catch (...)                                                                                                                                               \
    {                                                                                                                                                         \
        SET_ERROR(ERR_CODE_UNKNOWN_EXCEPTION, ERR_MESSAGE_UNKNOWN_EXCEPTION, "...");                                                                          \
        return failReturn;                                                                                                                                    \
    }
#else
#define CATCH_AND_RETURN(failReturn)                                                     \
    catch (std::exception & ex)                                                          \
    {                                                                                    \
        SET_ERROR(ERR_CODE_GENERAL_EXCEPTION, ERR_MESSAGE_GENERAL_EXCEPTION, ex.what()); \
        return failReturn;                                                               \
    }                                                                                    \
    catch (const char *error)                                                            \
    {                                                                                    \
        SET_ERROR(ERR_CODE_UNKNOWN_EXCEPTION, ERR_MESSAGE_UNKNOWN_EXCEPTION, error);     \
        return failReturn;                                                               \
    }                                                                                    \
    catch (...)                                                                          \
    {                                                                                    \
        SET_ERROR(ERR_CODE_UNKNOWN_EXCEPTION, ERR_MESSAGE_UNKNOWN_EXCEPTION, "...");     \
        return failReturn;                                                               \
    }
#endif

// 字符串拷贝，适用于目标变量用字符数组定义，因此明确知道内存宽度。
#define STRING_COPY(src, dst)                                             \
    {                                                                     \
        std::string sourceString = src;                                   \
        int32_t len = (int32_t)strlen(sourceString.c_str());              \
        len = MIN((int32_t)sizeof(dst), len);                             \
        std::copy(sourceString.c_str(), sourceString.c_str() + len, dst); \
        dst[len - 1] = '\0';                                              \
    }

// 字节拷贝
#define BYTE_COPY(src, dst, len)                                   \
    {                                                              \
        BYTE *pDest = reinterpret_cast<BYTE *>(dst);               \
        const BYTE *pSource = reinterpret_cast<const BYTE *>(src); \
        std::copy(pSource, pSource + len, pDest);                  \
    }

#define CHECK_NULL_POINTER(myPointer, failValue)                                       \
    {                                                                                  \
        if (myPointer == nullptr)                                                      \
        {                                                                              \
            SET_ERROR_(ERR_CODE_PPARA_IS_NULL, ERR_MESSAGE_PPARA_IS_NULL, #myPointer); \
            return failValue;                                                          \
        }                                                                              \
    }

class ConfigINI
{
public:
    static ConfigINI &GetInstance();
    std::string GetString(const std::string &key, std::string defaultValue = "");
    int32_t GetInt(const std::string &key, int32_t defaultValue = 0);
    double GetDouble(const std::string &key, double defaultValue = 0.0);
    ConfigINI(std::string iniFile = "");
    void LoadIniFile();

private:
    std::unordered_map<std::string, std::string> config_map_;
    std::mutex config_mutex_;
    std::filesystem::path config_path_;
};

// Redis连接管理器（带重连机制）
class RedisManager
{
public:
    enum class ConnectionState
    {
        DISCONNECTED,
        CONNECTED,
        CONNECT_ERROR
    };

    RedisManager(const std::string &host, int32_t port, int32_t socket_timeout_ms = 5000, int32_t connect_timeout_ms = 5000);
    ~RedisManager();
    int64_t getLastActiveTime() const;
    ConnectionState getState();
    void subscribe(const std::string &channel, std::function<void(const std::string &, const std::string &)> callback);
    bool consume();
    void disconnect();
    std::string ping();
    int64_t publish(std::string theme, std::string message);

private:
    void connect();
    void reconnect();
    std::string host_;
    int32_t port_;
    std::shared_ptr<sw::redis::Redis> redis_;
    std::shared_ptr<sw::redis::Subscriber> subscriber_;
    std::mutex mutex_;
    std::atomic<bool> should_stop_;
    const int32_t socket_timeout_;          // socket超时(ms)
    const int32_t connect_timeout_;         // 连接超时(ms)
    std::atomic<int64_t> last_active_time_; // 最后收到消息的时间戳
    std::atomic<ConnectionState> state_;    // 连接状态
};

namespace JsonUtils
{
    inline std::string get_string(const boost::json::object &jo, const std::string &field)
    {
        if (!jo.contains(field) || jo.at(field).is_null())
        {
            STD_CERR << _S_("[%s/%s-%d]", __FILE__, __FUNCTION__, __LINE__)
                     << _S_("json Field %s not exists or is null.", field.c_str()) << STD_ENDL;
            return "";
        }
        if (!jo.at(field).is_string())
        {
            STD_CERR << _S_("[%s/%s-%d]", __FILE__, __FUNCTION__, __LINE__)
                     << _S_("json Field %s is not a string value.", field.c_str()) << STD_ENDL;
            return "";
        }
        return jo.at(field).as_string().c_str();
    }

    template <typename T>
    inline T get_int(const boost::json::object &jo, const std::string &field)
    {
        if (!jo.contains(field) || jo.at(field).is_null())
        {
            STD_CERR << _S_("[%s/%s-%d]", __FILE__, __FUNCTION__, __LINE__)
                     << _S_("json Field %s not exists or is null.", field.c_str()) << STD_ENDL;
            return 0;
        }

        try
        {
            if (jo.at(field).is_int64())
                return static_cast<T>(jo.at(field).as_int64());
            if (jo.at(field).is_uint64())
                return static_cast<T>(jo.at(field).as_uint64());
            if (jo.at(field).is_string())
                return static_cast<T>(std::stoll(jo.at(field).as_string().c_str()));

            STD_CERR << _S_("[%s/%s-%d]", __FILE__, __FUNCTION__, __LINE__)
                     << _S_("json Field %s is not a integer value.", field.c_str()) << STD_ENDL;
        }
        catch (const std::exception &e)
        {
            STD_CERR << _S_("[%s/%s-%d]", __FILE__, __FUNCTION__, __LINE__)
                     << _S_("Error parsing field %s: %s", field.c_str(), e.what()) << STD_ENDL;
        }
        return 0;
    }
}

#endif
